package com.alone.jpa.query.wrapper;

import com.alone.jpa.query.ext.HqlFormatter;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;

/**
 * 查询包装器根接口<p/>
 *
 * @see JpaSpecificationExecutor
 *
 * @author Alone
 */
public interface ISpecificationWrapper<Type, Col, Children extends ISpecificationWrapper<Type, Col, Children>> {

    Children eq(boolean condition, Col column, Object value);

    default Children eq(Col column, Object value) {
        return eq(true, column, value);
    }

    Children ne(boolean condition, Col column, Object value);

    default Children ne(Col column, Object value) {
        return ne(true, column, value);
    }

    Children ge(boolean condition, Col column, Object value);

    default Children ge(Col column, Object value) {
        return ge(true, column, value);
    }

    Children le(boolean condition, Col column, Object value);

    default Children le(Col column, Object value) {
        return le(true, column, value);
    }

    Children gt(boolean condition, Col column, Object value);

    default Children gt(Col column, Object value) {
        return gt(true, column, value);
    }

    Children lt(boolean condition, Col column, Object value);

    default Children lt(Col column, Object value) {
        return lt(true, column, value);
    }

    Children between(boolean condition, Col column, Object value1, Object value2);

    default Children between(Col column, Object value1, Object value2) {
        return between(true, column, value1, value2);
    }

    Children notBetween(boolean condition, Col column, Object value1, Object value2);

    default Children notBetween(Col column, Object value1, Object value2) {
        return notBetween(true, column, value1, value2);
    }

    Children like(boolean condition, Col column, Object value);

    default Children like(Col column, Object value) {
        return like(true, column, value);
    }

    Children notLike(boolean condition, Col column, Object value);

    default Children notLike(Col column, Object value) {
        return notLike(true, column, value);
    }

    Children likeRight(boolean condition, Col column, Object value);

    default Children likeRight(Col column, Object value) {
        return likeRight(true, column, value);
    }

    Children notLikeRight(boolean condition, Col column, Object value);

    default Children notLikeRight(Col column, Object value) {
        return notLikeRight(true, column, value);
    }

    Children likeLeft(boolean condition, Col column, Object value);

    default Children likeLeft(Col column, Object value) {
        return likeLeft(true, column, value);
    }

    Children notLikeLeft(boolean condition, Col column, Object value);

    default Children notLikeLeft(Col column, Object value) {
        return notLikeLeft(true, column, value);
    }

    Children isNull(boolean condition, Col column);

    default Children isNull(Col column) {
        return isNull(true, column);
    }

    Children isNotNull(boolean condition, Col column);

    default Children isNotNull(Col column) {
        return isNotNull(true, column);
    }

    Children in(boolean condition, Col column, Collection<?> value);

    default Children in(Col column, Collection<?> value) {
        return in(true, column, value);
    }

    Children notIn(boolean condition, Col column, Collection<?> value);

    default Children notIn(Col column, Collection<?> value) {
        return notIn(true, column, value);
    }


    /*************** 添加sql片段 只支持单表的 ***************/
    Children apply(boolean condition, String hql);

    default Children apply(String hql) {
        return apply(true, hql);
    }

    default Children apply(boolean condition, String hqlTemp, Object ... values) {
        return apply(condition, HqlFormatter.of(hqlTemp, values));
    }

    default Children apply(String hqlTemp, Object ... values) {
        return apply(true, hqlTemp, values);
    }

    Children apply(boolean condition, HqlFormatter formatter);

    default Children apply(HqlFormatter formatter) {
        return apply(true, formatter);
    }

    /**
     * 用于支持动态拼接SpecificationWrapper<p/>
     * func(i -> if(yourCondition) {i.eq("id", 1)} else {i.ne("id", 1)})
     */
    Children func(boolean condition, Consumer<Children> consumer);

    default Children func(Consumer<Children> consumer) {
        return func(true, consumer);
    }

    /**
     * 例：eq("id",1).or().eq("name","老王")---> and (id = 1 or name = '老王')
     */
    Children or(boolean condition);

    default Children or() {
        return or(true);
    }

    /**
     * or(i -> i.eq("name", "李白").ne("status", "活着"))--->and (name = '李白' or status <> '活着')
     */
    Children or(boolean condition, Consumer<Children> consumer);

    default Children or(Consumer<Children> consumer) {
        return or(true, consumer);
    }

    /**
     * and(i -> i.eq("name", "李白").ne("status", "活着"))--->and (name = '李白' and status <> '活着')
     */
    Children and(boolean condition, Consumer<Children> consumer);

    default Children and(Consumer<Children> consumer) {
        return and(true, consumer);
    }

    /**
     * 获取当前装配好的Predicate
     */
    List<Predicate> getPredicates(Root<Type> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);

    /**
     * 将当前条件包装成Specification
     * @return Specification
     */
    Specification<Type> wrap();


    /*************** 比较同一张表的不同字段 ***************/
    Children eqCol(boolean condition, Col column1, Col column2);

    default Children eqCol(Col column1, Col column2) {
        return eqCol(true, column1, column2);
    }

    Children neCol(boolean condition, Col column1, Col column2);

    default Children neCol(Col column1, Col column2) {
        return neCol(true, column1, column2);
    }

    Children geCol(boolean condition, Col column1, Col column2);

    default Children geCol(Col column1, Col column2) {
        return geCol(true, column1, column2);
    }

    Children leCol(boolean condition, Col column1, Col column2);

    default Children leCol(Col column1, Col column2) {
        return leCol(true, column1, column2);
    }

    Children gtCol(boolean condition, Col column1, Col column2);

    default Children gtCol(Col column1, Col column2) {
        return gtCol(true, column1, column2);
    }

    Children ltCol(boolean condition, Col column1, Col column2);

    default Children ltCol(Col column1, Col column2) {
        return ltCol(true, column1, column2);
    }

}
